<!---
	Copyright 2010 Edward Trudeau, Jeremy Battle
    This software is freely available under the MIT License: http://www.opensource.org/licenses/mit-license.php
    http://ayc.googlecode.com
    
--->

<cfcomponent displayname="Validator" hint="I contain a library of standard validation functions.">
	<cffunction name="init" access="public" returntype="validator">
		<cfreturn this />
	</cffunction>
	
	<cffunction name="hasLen" returntype="boolean" output="false" hint="I check a value for length">
		<cfargument name="valToTest" required="yes" hint="Value to test" />
		<cfargument name="minLen" required="no" default="0" hint="Minimum string length" />
		<cfargument name="maxLen" required="no" default="0" hint="Maximum string length; defaults to infinity" />
		<cfif arguments.maxLen GT 0>
			<cfreturn iif(len(trim(arguments.valToTest)) GTE arguments.minLen AND len(trim(arguments.valToTest)) LTE arguments.maxLen, true, false) />
		<cfelse>
			<cfreturn iif(len(trim(arguments.valToTest)) GTE arguments.minLen, true, false) />
		</cfif>
	</cffunction>
	
	<cffunction name="isNum" returntype="boolean" output="false" hint="I verify that a value is numeric">
		<cfargument name="valToTest" required="yes" hint="Value to test" />
		<cfargument name="valType" required="yes" default="int" hint="The type of number.  Valid values are: int, tinyint, smallint, float" />
		<cfargument name="atLeast" required="no" default="" hint="The minimum value, if any, for the number" type="numeric" />
		<cfargument name="atMost" required="no" default="" hint="The maximum value, if any, for the number" type="numeric" />
		
		<!--- set up the boundaries for tinyints --->
		<cfif arguments.valType IS "tinyint" AND (arguments.atLeast EQ "" OR arguments.atLeast LT 0)>
			<cfset arguments.atLeast = 0 />
		</cfif> 
		<cfif arguments.valType IS "tinyint" AND (arguments.atMost EQ "" OR arguments.atMost GT 255)>
			<cfset arguments.atMost = 255 />
		</cfif> 
		
		<!--- set up the boundaries for smallints --->
		<cfif arguments.valType IS "smallint" AND (arguments.atLeast EQ "" OR arguments.atLeast LT -32768)>
			<cfset arguments.atLeast = -32768 />
		</cfif> 
		<cfif arguments.valType IS "smallint" AND (arguments.atMost EQ "" OR arguments.atMost GT 32767)>
			<cfset arguments.atMost = 32767 />
		</cfif> 
		
		<!--- set up the boundaries for ints --->
		<cfif arguments.valType IS "int" AND (arguments.atLeast EQ "" OR arguments.atLeast LT -2147483648)>
			<cfset arguments.atLeast = -2147483648 />
		</cfif> 
		<cfif arguments.valType IS "smallint" AND (arguments.atMost EQ "" OR arguments.atMost GT 2147483647)>
			<cfset arguments.atMost = 2147483647 />
		</cfif> 
		
		<cfif arguments.valType NEQ "float">
			<cfreturn iif(isNumeric(arguments.valToTest) AND arguments.valToTest GTE arguments.atLeast AND arguments.valToTest LTE arguments.atMost AND int(arguments.valToTest) EQ arguments.valToTest, true, false) />
		<cfelse>
			<cfreturn iif(isNumeric(arguments.valToTest) AND arguments.valToTest GTE arguments.atLeast AND arguments.valToTest LTE arguments.atMost, true, false) />
		</cfif>
		
	</cffunction>
	
	<cffunction name="isValidDate" returntype="boolean" output="false" hint="I verify that a value is a date falling within the specified limits.">
		<cfargument name="valToTest" required="yes" hint="Value to test" />
		<cfargument name="minVal" required="no" default="" hint="Minimum value for the range" />
		<cfargument name="maxVal" required="no" default="" hint="Maximum value for the range" />
		
		<cfset var minDate = "" />
		<cfset var maxDate = "" />
		
		<!--- validate min and max values --->
		<cfif len(arguments.minVal) AND isDate(arguments.minVal)>
			<cfset minDate = arguments.minVal />
		<cfelseif len(arguments.minVal)>
			<cftry>
				<cfif isDate(evaluate(arguments.minVal))>
					<cfset minDate = evaluate(arguments.minVal) />
				</cfif>
			
				<cfcatch type="expression">
					<cfset throw("validDate.InvalidExpression", "The minimum date value passed to validDate (#arguments.minVal#) is neither a date nor a ColdFusion expression that evaluates to a date.") />
				</cfcatch>
			</cftry>
		</cfif>
		<cfif len(arguments.maxVal) AND isDate(arguments.maxVal)>
			<cfset maxDate = arguments.maxVal />
		<cfelseif len(arguments.maxVal)>
			<cftry>
				<cfif isDate(evaluate(arguments.maxVal))>
					<cfset maxDate = evaluate(arguments.maxVal) />
				</cfif>
			
				<cfcatch type="expression">
					<cfset throw("validDate.InvalidExpression", "The maximum date value passed to validDate (#arguments.maxVal#) is neither a date nor a ColdFusion expression that evaluates to a date.") />
				</cfcatch>
			</cftry>
		</cfif>
		
		<cfif len(minDate) AND len(maxDate)>
			<cfreturn iif(isDate(arguments.valToTest) AND minDate LTE arguments.valToTest AND maxDate GTE arguments.valToTest, true, false) />
		<cfelseif len(minDate)>
			<cfreturn iif(isDate(arguments.valToTest) AND minDate LTE arguments.valToTest, true, false) />
		<cfelseif len(maxDate)>
			<cfreturn iif(isDate(arguments.valToTest) AND maxDate GTE arguments.valToTest, true, false) />
		<cfelse>
			<cfreturn iif(isDate(arguments.valToTest), true, false) />
		</cfif>
	</cffunction>
	
	<cffunction name="throw" returntype="void" hint="I throw errors from the data validator service." output="false">
		<cfargument name="ErrorType" required="true" type="string" hint="The error type.">
		<cfargument name="ErrorMessage" required="true" type="any" hint="The message to display.">
		<cfthrow type="Validator.#arguments.ErrorType#" message="#ErrorMessage#" />
	</cffunction>
</cfcomponent>

